#ifndef MODEL_H
#define MODEL_H

#include <QtCore>

#include "../filehandling/FileType.h"

namespace Server {

/**
 * @brief Struktura opisująca podstawowe informacje o pliku
 **/
struct FileDesc {
	/// Nazwa/możliwe nazwy pliku
	QVector<QString> fname;

	/// Rozmiar pliku w bajtach
	int size;

	/// Suma kontrolna
	QByteArray hash;

	/// typ pliku
	Common::FileType type;

	/// całkowita ilość klientów posiadających dany plik
	int total_seeds;

	/// liczba zalogowanych klientów posiadających dany plik
	int active_seeds;

	///Vector userów posiadajacych plik
	QVector<int> owners;
};

/**
 * @brief Klasa opisująca użytkownika
 **/

class User{
private:
    /// ID użytkownika w bazie servera
    int id_;

    /// Nazwa hosta na kórej aktulanie urzęduje użytkownik
    QString host_;
public:
    /// Lista plików jakie dany user posiada
    //QList<FileDesc> owned_;
    QList<QByteArray> owned_;

    User();

    /**
      *Pobranie listy plików posiadanych przez klienta
      *
      *@return Lista plików posiadanych przez klienta
      **/
//    QList<FileDesc> getOwnedFiles();

    /**
      *Pobranie nazwy hosta klienta
      *
      *@return Aktualny adres/nazwa hosta
      **/
    QString getHost();

    /**
      *Dodanie nowego pliku do listy posiadanych przez klienta
      *
      *@param file Unikatowy hash opisujący dodawany plik
      **/
    void addFile(/*FileDesc*/QByteArray &file);

    /**
      *Ustawienie nazwy hosta klienta
      *
      *@param host referencja na łańcuhc znaków opisujących host klienta
      **/
    void setHost(QString &host);

    /**
      *Ustawienie ID klienta
      *
	  *@param id numer ID, który zosatnie przydzielony klientowi
      **/
    void setID(int id);

    /**
      *Pobranie ID użytkownika
      *
      *@return ID użytkownika
      **/
    int getID();

    /**
      *Przeciążony operator porównania
      **/
    bool operator==(const User &s) const;
};



/**
 * @brief Główny moduł serwera odpowiedzialny za cała jego funkcjonalność.
 *
 * Przechowuje listę plików wraz z danymi o nich (suma kontrolna, rozmiar, lista klientów posiadających
 * dany plik), listę zalogowanych klientów oraz umożliwia dokonywanie wyszukiwania w
 * przechowywanych plikach. Podczas wyszukiwania oprócz samej nazwy pliku brane pod
 * uwagę są też inne kryteria, takie jak typ pliku (można określić czy szukamy plików
 * dowolnego typu, czy np. samych filmów bądź muzyki) bądź wielkość pliku (aby szukając
 * czegoś małego, np. pojedynczego dokumentu o dość popularnej nazwie, od razu na tym
 * etapie odfiltrować część niepoprawnych wyników).
 **/
class Model
{
public:
	/**
	 * Propozycja: \n
	 * W konstruktorze powinny zostać wczytane pliki bazy danych
	 * plików oraz klientów.
	 **/
	Model();

	/**
	 * Propozycja: \n
	 * W destruktorze powinien nastapić zapis danych na dysku.
	 **/
	~Model();

	/**
	 * Wymuszenie zapisania danych
	 **/
	void saveAll();

	/**
	 * Funkcja sprawdzająca czy user o danym ID istnieje w bazie
	 *
	 * @param id ID szukango użytkownika
	 * @param active
	 *
	 * @return Zwraca pozycje w zadanej liście jeśli użytkownik istnieje lub -1 w przeciwnym wypadku
	 **/
	int findUser(int id, bool active = false);

	/**
	 * Rejestracja nowego użytkownika
	 *
	 * @return ID nowego użytkownika
	 **/
	int registerUser();

	/**
	 * Dodanie klienta o danym id do listy aktywnych. \n
	 * \n
	 * \b ficzer:
	 * W przypadku, gdy dany klient nie występuje w ogóle w bazie
	 * klientów należy go także dodać do listy wszystkich klientów.
	 *
	 * @param id identyfikator klienta
	 **/
	void loginClient(int id);

	/**
	 * Usunięcie z listy aktywnych klienta o danym id
	 *
	 * @param id identyfikator klienta
	 **/
	void logoutClient(int id);

	/**
	 * Dodanie do bazy danych nowego pliku o określonych paramtrach.
	 * W przypadku, gdy ten sam plik jest już zapisany w bazie
	 * do listy klientów posiadających go dopisywany jest klient zgłaszający
	 * nowy plik oraz ewentualnie dopisywana jest kolejna nazwa, pod którą
	 * jest znany ten plik (może być to wykorzystane w wyszukiwaniu).\n
	 * \n
	 * Tożsamość plików określa się po porównaniu sumy kontrolnej i wielkości
	 *
	 * @param fname nazwa pliku
	 * @param size rozmiar pliku w bajtach
	 * @param hash suma kontrolna
	 * @param type typ pliku
	 * @param client_id identyfikator klienta zgłaszającego plik
	 *
	 * @return true jeśli dodawanego pliku nie było jeszcze w bazie, \n
	 *         false jeśli plik już istniaj w bazie danych
	 **/
	bool addFile(QString fname, int size, QByteArray hash, Common::FileType type, int client_id);

	/**
	 * Usunięcie z właścicieli pliku klienta o podanym identyfikatorze.
	 * W przypadku, gdy był to ostatni klient posiadający ten plik z bazy
	 * usuwana jest cała informacja o tym pliku.\n
	 * \n
	 * Tożsamość plików określa się po porównaniu sumy kontrolnej i wielkości
	 *
	 * @param fname nazwa pliku
	 * @param size rozmiar pliku
	 * @param hash suma kontrolna
	 * @param client_id identyfikator klienta
	 *
	 * @return true jeśli usunięto ostatniego właściciela, \n
	 *         false jeśli plik pozostaje nadal w bazie danych
	 **/
	bool removeFile(QString fname, int size, QByteArray hash, int client_id);

	/**
	 * Wyszukanie wszystkich plików pasujących do zadanych kryteriów wyszukiwania.
	 * W przypadku braku pasujących plików zwracany wynik jest pusty.
	 *
	 * @param query zapytanie w postaci prostego napisu bądź wyrażenia regularnego
	 * @param type typ wyszukiwanego pliku
	 * @param size_min minimalny rozmiar poszukiwango pliku (w bajtach)
	 * @param size_max maksymalny rozmiar poszukiwango pliku (w bajtach)
	 *
	 * @return lista znalezionych plików pasujących do zadanych kryteriów
	 **/
	const QVector<FileDesc> find(QString query, Common::FileType type = Common::ftAny, int size_min = 0, int size_max = 0);

	/**
	 * Wyszukanie wszystkich aktualnie podłączonych klientów posiadających dany plik.
	 * W przypadku braku aktywnych klientów zwracany wynik jest pusty.
	 *
	 * @param size rozmiar pliku
	 * @param hash suma kontrolna pliku
	 *
	 * @return lista aktywnych klientów (identyfikatorów) posiadających dany plik
	 **/
	const QVector<int> findSeeds(int size, QByteArray hash);

	/*
	  Możesz dodać jeszcze jakieś ciekawe ficzery, w stylu znajdowanie wszystkich plików
	  które posiada dany klient. Jak Ci coś fajnego do głowy wpadnie to fajno :-)
	  */

private:
	/*
	  Tutaj dopisuj sobie co Ci się tylko podoba :P
	  Dorób sobie jeszcze ile chcesz klas dodatkowych do tej bazy danych, byle
	  funkcje które napisałem na górze działały tak, jak napisałem :D
	  */

	QList<User> users_;
	QList<User> activeUsers_;

	QMap<QByteArray, FileDesc> files_;

	QFile *data_;
};

} // namespace Server

#endif // MODEL_H
